#include "qdraw.h"

#include <vector>
#include <string>

#include <gdiplusfont.h>

QNamespaceStart(Qui)

_QShapeServer __Shape_server_class;

void QRenderimageAlpha(IMAGE* image)
{
	BYTE a, r, g, b;

	DWORD* image_buffer = GetImageBuffer(image);

	for (int image_count = image->getwidth() * image->getheight() - 1; image_count >= 0;
		--image_count)
	{
		if (image_buffer[image_count] == 0)
		{
			a = 0;
		}
		else
		{
			a = 255;
		}

		r = GetRValue(image_buffer[image_count]) * a / 255;
		g = GetGValue(image_buffer[image_count]) * a / 255;
		b = GetBValue(image_buffer[image_count]) * a / 255;

		image_buffer[image_count] = a << 24 | RGB(r, g, b);
	}
}

HDC QGetImageHDC(IMAGE* image)
{
	if (image != nullptr)
	{
		return (HDC) * ((QWORD*)image + 3);
	}

	return GetImageHDC(nullptr);
}

void QPutimage(int x, int y, IMAGE* image_beput, 
			int transparency, IMAGE* target)
{
	HDC target_dc  = QGetImageHDC(target);
	HDC image_dc   = QGetImageHDC(image_beput);

	int width  = image_beput->getwidth();
	int height = image_beput->getheight();

	BLENDFUNCTION blend_function = {  AC_SRC_OVER, 0, static_cast<BYTE>(transparency), AC_SRC_ALPHA };
	AlphaBlend(target_dc, x, y, width, height, 
				image_dc, 0, 0, width, height, 
				blend_function);
}
void QGetimage(int x, int y, int width, int height, IMAGE* image_get)
{
	IMAGE image;

	getimage(&image, x, y, width, height);

	*image_get = image;
}

void QDrawEllipse(int x1, int y1, int x2, int y2,
					IMAGE* result_image)
{
	using namespace Gdiplus;

	int width   = x2 - x1;
	int height  = y2 - y1;

	
	LINESTYLE current_line_style;

	getlinestyle(&current_line_style);
	IMAGE     result(width + current_line_style.thickness, height + current_line_style.thickness);

	Graphics draw_graphics(GetImageHDC(&result));
	Pen      draw_pen(Color(GetRValue(getcolor()), GetGValue(getcolor()), GetBValue(getcolor())), 
		static_cast<REAL>(current_line_style.thickness));

	QShapeSetHighQuality(draw_graphics);

	draw_graphics.DrawEllipse(&draw_pen, 0, 0, width, height);

	QPutimage(x1, y1, &result);

	if (result_image != nullptr)
	{
		*result_image = result;
	}
}
void QDrawRectangle(int x1, int y1, int x2, int y2,
					IMAGE* result_image)
{
	using namespace Gdiplus;

	int width   = x2 - x1;
	int height  = y2 - y1;

	LINESTYLE current_line_style;

	getlinestyle(&current_line_style);
	IMAGE     result(width + current_line_style.thickness, height + current_line_style.thickness);

	Graphics draw_graphics(GetImageHDC(&result));
	Pen      draw_pen(Color(GetRValue(getcolor()), GetGValue(getcolor()), GetBValue(getcolor())), 
		static_cast<REAL>(current_line_style.thickness));

	QShapeSetHighQuality(draw_graphics);

	draw_graphics.DrawRectangle(&draw_pen, 0, 0, width, height);

	QPutimage(x1, y1, &result);
}
void QDrawPolygon(int x, int y, const POINT* points, int point_number)
{
	using namespace Gdiplus;

	PointF* point_f_s = new PointF[point_number];

	int mini_x = INT_MAX;
	int mini_y = INT_MAX;

	int max_x  = 0;
	int max_y  = 0;

	for (int count = 0; count < point_number; ++count)
	{
		point_f_s[count].X = points[count].x - x;
		point_f_s[count].Y = points[count].y - y;

		if (points[count].x < mini_x)
		{
			mini_x = points[count].x  - x;
		}
		if (points[count].y < mini_y)
		{
			mini_y = points[count].y - y;
		}
		if (points[count].x > max_x)
		{
			max_x = points[count].x  - x;
		}
		if (points[count].y > max_y)
		{
			max_y = points[count].y  - y;
		}
	}
	
	LINESTYLE current_line_style;

	getlinestyle(&current_line_style);
	IMAGE     result(max_x + x + max_x - mini_x + current_line_style.thickness, 
					 max_y + y + max_y - mini_y + current_line_style.thickness);

	Graphics draw_graphics(GetImageHDC(&result));
	Pen      draw_pen(Color(GetRValue(getcolor()), GetGValue(getcolor()), GetBValue(getcolor())), 
		static_cast<REAL>(current_line_style.thickness));

	QShapeSetHighQuality(draw_graphics);

	draw_graphics.DrawPolygon(&draw_pen, point_f_s, point_number);

	QPutimage(x, y, &result);
}

void QDrawFillEllipse(int x1, int y1, int x2, int y2,
					IMAGE* result_image)
{
	using namespace Gdiplus;

	int width   = x2 - x1;
	int height  = y2 - y1;

	LINESTYLE current_line_style;

	getlinestyle(&current_line_style);
	IMAGE     result(width + current_line_style.thickness, height + current_line_style.thickness);

	Graphics   draw_graphics(GetImageHDC(&result));
	SolidBrush draw_brush(Color(GetRValue(getfillcolor()), GetGValue(getfillcolor()), GetBValue(getfillcolor())));

	QShapeSetHighQuality(draw_graphics);

	draw_graphics.FillEllipse(&draw_brush, 0, 0, width, height);

	QPutimage(x1, y1, &result);
}
void QDrawFillRectangle(int x1, int y1, int x2, int y2,
					IMAGE* result_image)
{
	using namespace Gdiplus;

	int width   = x2 - x1;
	int height  = y2 - y1;

	LINESTYLE current_line_style;

	getlinestyle(&current_line_style);
	IMAGE     result(width, height);

	Graphics   draw_graphics(GetImageHDC(&result));
	SolidBrush draw_brush(Color(GetRValue(getfillcolor()), GetGValue(getfillcolor()), GetBValue(getfillcolor())));

	QShapeSetHighQuality(draw_graphics);

	draw_graphics.FillRectangle(&draw_brush, 0, 0, width, height);

	QPutimage(x1, y1, &result);
}
void QDrawFillPolygon(int x, int y, const POINT* points, int point_number,
					IMAGE* result_image)
{
	using namespace Gdiplus;

	PointF* point_f_s = new PointF[point_number];

	int mini_x = INT_MAX;
	int mini_y = INT_MAX;

	int max_x  = 0;
	int max_y  = 0;

	for (int count = 0; count < point_number; ++count)
	{
		point_f_s[count].X = points[count].x - x;
		point_f_s[count].Y = points[count].y - y;

		if (points[count].x < mini_x)
		{
			mini_x = points[count].x  - x;
		}
		if (points[count].y < mini_y)
		{
			mini_y = points[count].y - y;
		}
		if (points[count].x > max_x)
		{
			max_x = points[count].x  - x;
		}
		if (points[count].y > max_y)
		{
			max_y = points[count].y  - y;
		}
	}
	
	LINESTYLE current_line_style;

	getlinestyle(&current_line_style);
	IMAGE     result(max_x + x + max_x - mini_x + current_line_style.thickness, 
					 max_y + y + max_y - mini_y + current_line_style.thickness);

	Graphics    draw_graphics(GetImageHDC(&result));
	SolidBrush  draw_pen(Color(GetRValue(getfillcolor()), GetGValue(getfillcolor()), GetBValue(getfillcolor())));

	QShapeSetHighQuality(draw_graphics);

	draw_graphics.FillPolygon(&draw_pen, point_f_s, point_number);

	QPutimage(x, y, &result);
}

void QDrawSoildEllipse(int x1, int y1, int x2, int y2,
					IMAGE* result_image)
{
	using namespace Gdiplus;

	int width   = x2 - x1;
	int height  = y2 - y1;

	LINESTYLE current_line_style;

	getlinestyle(&current_line_style);
	IMAGE     result(width + current_line_style.thickness, height + current_line_style.thickness);

	Graphics   draw_graphics(GetImageHDC(&result));
	SolidBrush draw_brush(Color(GetRValue(getfillcolor()), GetGValue(getfillcolor()), GetBValue(getfillcolor())));
	Pen        draw_pen(Color(GetRValue(getlinecolor()), GetGValue(getlinecolor()), GetBValue(getlinecolor())));

	QShapeSetHighQuality(draw_graphics);

	draw_graphics.FillEllipse(&draw_brush, 0, 0, width, height);
	draw_graphics.DrawEllipse(&draw_pen, 0, 0, width, height);

	QPutimage(x1, y1, &result);
}
void QDrawSoildRectangle(int x1, int y1, int x2, int y2,
					IMAGE* result_image)
{
	using namespace Gdiplus;

	int width   = x2 - x1;
	int height  = y2 - y1;

	LINESTYLE current_line_style;

	getlinestyle(&current_line_style);
	IMAGE     result(width + current_line_style.thickness, height + current_line_style.thickness);

	Graphics   draw_graphics(GetImageHDC(&result));
	SolidBrush draw_brush(Color(GetRValue(getfillcolor()), GetGValue(getfillcolor()), GetBValue(getfillcolor())));
	Pen        draw_pen(Color(GetRValue(getlinecolor()), GetGValue(getlinecolor()), GetBValue(getlinecolor())));

	QShapeSetHighQuality(draw_graphics);

	draw_graphics.FillRectangle(&draw_brush, 0, 0, width, height);
	draw_graphics.DrawRectangle(&draw_pen, 0, 0, width, height);

	QPutimage(x1, y1, &result);
}
void QDrawSoildPolygon(int x, int y, POINT* points, int point_number,
					IMAGE* result_image)
{
	using namespace Gdiplus;

	PointF* point_f_s = new PointF[point_number];

	int mini_x = INT_MAX;
	int mini_y = INT_MAX;

	int max_x  = 0;
	int max_y  = 0;

	for (int count = 0; count < point_number; ++count)
	{
		point_f_s[count].X = points[count].x - x;
		point_f_s[count].Y = points[count].y - y;

		if (points[count].x < mini_x)
		{
			mini_x = points[count].x  - x;
		}
		if (points[count].y < mini_y)
		{
			mini_y = points[count].y - y;
		}
		if (points[count].x > max_x)
		{
			max_x = points[count].x  - x;
		}
		if (points[count].y > max_y)
		{
			max_y = points[count].y  - y;
		}
	}
	
	LINESTYLE current_line_style;

	getlinestyle(&current_line_style);
	IMAGE     result(max_x + x + max_x - mini_x + current_line_style.thickness, 
					 max_y + y + max_y - mini_y + current_line_style.thickness);

	Graphics    draw_graphics(GetImageHDC(&result));
	SolidBrush  draw_brush(Color(GetRValue(getfillcolor()), GetGValue(getfillcolor()), GetBValue(getfillcolor())));
	Pen         draw_pen(Color(GetRValue(getlinecolor()), GetGValue(getlinecolor()), GetBValue(getlinecolor())));

	QShapeSetHighQuality(draw_graphics);

	draw_graphics.FillPolygon(&draw_brush, point_f_s, point_number);
	draw_graphics.DrawPolygon(&draw_pen,   point_f_s, point_number);

	QPutimage(x, y, &result);
}

void QLoadImage(IMAGE* image, LPCTSTR image_path, int width, int height,
					bool resize)
{
	IMAGE temp_image;

	loadimage(&temp_image, image_path, width, height, resize);

	if (image != nullptr)
	{
		*image = temp_image;
	}
}

void QLoadImage(IMAGE* image, LPCTSTR resouce_type, LPCTSTR source_name, int width, int height,
					bool resize)
{
	IMAGE temp_image;

	loadimage(&temp_image, resouce_type, source_name, width, height, resize);

	if (image != nullptr)
	{
		*image = temp_image;
	}
}

void QOutTextXy(int x, int y, LPCTSTR string)
{
	int max_height = 0;
	int temp_x     = x;

	for (int count = 0; count < lstrlen(string); ++count)
	{
		if (max_height < textheight(string[count]))
		{
			max_height = textheight(string[count]);
		}

		if (string[count] == '\n')
		{
			y += max_height;
			x  = temp_x;

			max_height = 0;

			++count;
		}

		outtextxy(x, y, string[count]);

		x += textwidth(string[count]);
	}
}
void QOutTextCenter(IMAGE* canvas, LPCTSTR string, bool focus)
{
	IMAGE temp;

	if (focus == true)
	{
		SetWorkingImage(canvas);

		std::vector<std::wstring> string_list;
		std::wstring single_string;

		int x = 0;
		int y = canvas->getheight();

		int y_count = 0;

		for (int count = 0; count < lstrlen(string); ++count)
		{
			if (string[count] == '\n')
			{
				string_list.push_back(single_string);
				y_count += textwidth(single_string.c_str()) / 2;

				single_string.clear();

				++count;
			}

			single_string.push_back(string[count]);
		}

		string_list.push_back(single_string);
		y_count += textwidth(single_string.c_str()) / 2;

		single_string.clear();

		y -= y_count * 2;

		for (auto& item : string_list)
		{
			x  = canvas->getwidth() / 2 -
				textwidth(item.c_str()) / 2;

			outtextxy(x, y, item.c_str());

			y -= textheight(item.c_str());
		}

		QRenderimageAlpha(canvas);

		SetWorkingImage(NULL);
	}
	else
	{
		SetWorkingImage(canvas);

		std::vector<std::wstring> string_list;
		std::wstring single_string;

		int x = 0;
		int y = 0;

		for (int count = 0; count < lstrlen(string); ++count)
		{
			if (string[count] == '\n')
			{
				string_list.push_back(single_string);
				single_string.clear();

				++count;
			}

			single_string.push_back(string[count]);
		}

		string_list.push_back(single_string);

		for (auto& item : string_list)
		{
			x  = canvas->getwidth() / 2 -
				textwidth(item.c_str()) / 2;

			outtextxy(x, y, item.c_str());

			y += textheight(item.c_str());
		}

		QRenderimageAlpha(&temp);

		SetWorkingImage(NULL);
	}

	if (canvas != nullptr)
	{
		*canvas = temp;
	}
}

int  QTextWidth(LPCTSTR string)
{
	int  width	   = 0;
	int  max_width = 0;

	for (int count = 0; count < lstrlen(string); ++count)
	{
		if (string[count] == '\n')
		{
			if (max_width <= width)
			{
				max_width = width;
			}

			width = 0;

			++count;
		}

		width += textwidth(string[count]);
	}

	if (max_width <= width)
	{
		max_width = width;
	}

	return max_width;
}
int  QTextHeight(LPCTSTR string)
{
	return textheight(string);
}

void QDrawShadow(Gdiplus::Graphics& graphics, Gdiplus::GraphicsPath& path, int shadow_pixel)
{
	using namespace Gdiplus;

	graphics.SetPageUnit(UnitPixel);

	GraphicsPath& shadow_path = *(path.Clone());

	Matrix shadow_matrix;
	shadow_matrix.Translate(shadow_pixel, shadow_pixel);

	shadow_path.Transform(&shadow_matrix);

	Region path_region(&path);
	Region shaow_region(&path);

	shaow_region.Exclude(&path_region);

	PathGradientBrush gradient_brush(&shadow_path);
	gradient_brush.SetCenterColor(RGB(0, 0, 0));

	Color colors[4] = {Color(0, 0, 0, 0), Color(4, 4, 4, 0), 
						Color(8, 8, 8, 0), Color(12, 12, 12, 0)};

	INT   count = 1;

	gradient_brush.SetSurroundColors(colors, &count);
	gradient_brush.SetFocusScales(0.75f, 0.75f);

	graphics.FillRegion(&gradient_brush, &shaow_region);
}

void QResizeImage(IMAGE* image, int width, int height)
{
	IMAGE temp = IMAGE(width, height);


}


QNamespaceEnd